package com.scpii.api.common.auth.client;

import java.util.Date;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.scpii.api.common.Constants;
import com.scpii.api.common.auth.AuthorizationRequest;
import com.scpii.api.common.auth.ClientAuthentication;
import com.scpii.api.common.exception.ClientNotFoundException;
import com.scpii.api.common.exception.InvalidClientException;
import com.scpii.api.domain.auth.ClientInfo;
import com.scpii.api.domain.auth.Devices;
import com.scpii.api.domain.auth.UserConfigs;
import com.scpii.api.domain.auth.UserDevices;
import com.scpii.api.domain.auth.UsersInfoDetails;
import com.scpii.api.persistence.auth.ClientInfoMapper;
import com.scpii.api.persistence.auth.DevicesMapper;
import com.scpii.api.persistence.auth.UserConfigsMapper;
import com.scpii.api.persistence.auth.UserDevicesMapper;
import com.scpii.api.persistence.auth.UsersInfoDetailsMapper;

@Component
@Transactional
public class DefaultClientDetailsService implements ClientDetailsService {

	@Resource
	private ClientInfoMapper clientInfoMapper;

	@Resource
	private UsersInfoDetailsMapper usersInfoDetailsMapper;

	@Resource
	private DevicesMapper devicesMapper;

	@Resource
	private UserDevicesMapper userDevicesMapper;

	@Resource
	private UserConfigsMapper userConfigsMapper;

	@Override
	public UsersInfoDetails loadAnonymousUsersInfoDetailsByDeviceId(
			String appId, String deviceId) {

		ClientInfo clientInfo = null;
		try {
			clientInfo = clientInfoMapper.selectByPrimaryKey(Long
					.valueOf(appId));
		} catch (NumberFormatException e) {
			throw new ClientNotFoundException("AppId " + appId + " not found");
		}
		if (clientInfo == null) {
			throw new ClientNotFoundException("AppId " + appId + " not found");
		}

		UsersInfoDetails usersInfoDetails = null;
		try {
			usersInfoDetails = usersInfoDetailsMapper
					.loadAnonymousUsersInfoDetailsByDeviceId(
							Long.valueOf(appId), deviceId);
		} catch (NumberFormatException e) {
			throw new ClientNotFoundException("AppId " + appId + " not found");
		}
		if (usersInfoDetails == null) {
			usersInfoDetails = new UsersInfoDetails();
			usersInfoDetails.setAppId(Long.valueOf(appId));
			usersInfoDetails.setUserName(deviceId);
			usersInfoDetails.setUserAilas(deviceId);
			usersInfoDetails.setCreateDt(new Date());
			usersInfoDetails.setPassword(DigestUtils
					.md5Hex(Constants.USER_DEFAULT_PSSWORD));
			usersInfoDetails.setPasswordFormat(Constants.USER_PASSWORD_FORMAT);
			usersInfoDetails.setUserType(Constants.USERS_TYPES.get("ANON"));
			usersInfoDetails.setAuthoritiesStr(Constants.ROLES
					.get("ROLE_CLIENT"));
			usersInfoDetails.setLastLoginDt(new Date());
			usersInfoDetails.setLastActivityDt(new Date());
			usersInfoDetailsMapper.insertSelective(usersInfoDetails);
			UserConfigs userConfigs = new UserConfigs();
			userConfigs.setUserId(usersInfoDetails.getId());
			usersInfoDetails.setLastLoginDt(new Date());
			usersInfoDetails.setLastActivityDt(new Date());
			userConfigsMapper.insertSelective(userConfigs);
		} else {
			usersInfoDetails.setLastLoginDt(new Date());
			usersInfoDetails.setLastActivityDt(new Date());
			usersInfoDetails.setUpdateDt(new Date());
			usersInfoDetailsMapper
					.updateByPrimaryKeySelective(usersInfoDetails);
		}
		usersInfoDetails.setPassword(clientInfo.getAppKey());
		return usersInfoDetails;
	}

	@Override
	public void storeDevice(AuthorizationRequest request,
			ClientAuthentication authentication) {
		UsersInfoDetails usersInfoDetails = (UsersInfoDetails) authentication
				.getPrincipal();
		Long appId = usersInfoDetails.getAppId();
		Long userId = usersInfoDetails.getId();
		String deviceId = request.getDeviceId();

		Map<String, String> params = request.getAuthorizationParameters();

		String deviceName = params.get("deviceName");
		String deviceType = params.get("deviceType");
		String buildPlatform = params.get("buildPlatform");
		String deviceModel = params.get("deviceModel");
		String phoneNumber = params.get("phoneNumber");
		String phoneType = params.get("phoneType");
		String systemVersion = params.get("systemVersion");
		String appVersion = params.get("appVersion");
		String installSource = params.get("installSource");
		String resolution = params.get("resolution");

		Devices recordDevices = new Devices();
		recordDevices.setDeviceId(deviceId);
		recordDevices.setAppId(appId);
		Devices persistDevices = devicesMapper.selectBySelective(recordDevices);
		if (persistDevices == null) {
			persistDevices = new Devices();
			persistDevices.setDeviceId(deviceId);
			persistDevices.setAppId(appId);
			persistDevices.setDeviceName(deviceName);
			persistDevices.setDeviceType(deviceType);
			persistDevices.setBuildPlatform(buildPlatform);
			persistDevices.setDeviceModel(deviceModel);
			persistDevices.setPhoneNumber(phoneNumber);
			persistDevices.setPhoneType(phoneType);
			persistDevices.setSystemVersion(systemVersion);
			persistDevices.setAppVersion(appVersion);
			persistDevices.setInstallSource(installSource);
			persistDevices.setResolution(resolution);
			persistDevices.setCreateBy(userId);
			persistDevices.setCreateDt(new Date());
			devicesMapper.insertSelective(persistDevices);
		} else {
			persistDevices.setDeviceName(deviceName);
			persistDevices.setDeviceType(deviceType);
			persistDevices.setBuildPlatform(buildPlatform);
			persistDevices.setDeviceModel(deviceModel);
			persistDevices.setPhoneNumber(phoneNumber);
			persistDevices.setPhoneType(phoneType);
			persistDevices.setSystemVersion(systemVersion);
			persistDevices.setAppVersion(appVersion);
			persistDevices.setInstallSource(installSource);
			persistDevices.setResolution(resolution);
			persistDevices.setUpdateBy(userId);
			persistDevices.setUpdateDt(new Date());
			devicesMapper.updateByPrimaryKeySelective(persistDevices);
		}
		usersInfoDetails.setDeviceId(persistDevices.getId());

		UserDevices userDevicesRecord = new UserDevices();
		userDevicesRecord.setUserId(userId);
		userDevicesRecord.setDeviceId(persistDevices.getId());

		UserDevices persistUserDevices = userDevicesMapper
				.selectBySelective(userDevicesRecord);
		if (persistUserDevices == null) {
			userDevicesRecord.setCreateBy(userId);
			userDevicesRecord.setCreateTime(new Date());
			userDevicesRecord.setStatus(Constants.USER_DEVICES_STATUS
					.get("ON_LINE"));
			userDevicesMapper.insertSelective(userDevicesRecord);
			userDevicesRecord.setUpdateBy(userId);
			userDevicesRecord.setStatus(Constants.USER_DEVICES_STATUS
					.get("OFF_LINE"));
			userDevicesMapper.updateStatus(userDevicesRecord);
		} else {
			persistUserDevices.setStatus(Constants.USER_DEVICES_STATUS
					.get("ON_LINE"));
			persistUserDevices.setUpdateTime(new Date());
			persistUserDevices.setUpdateBy(userId);
			userDevicesMapper.updateByPrimaryKey(persistUserDevices);
			persistUserDevices.setStatus(Constants.USER_DEVICES_STATUS
					.get("OFF_LINE"));
			userDevicesMapper.updateStatus(persistUserDevices);
		}
	}

	@Override
	public Devices loadDevicesByPrimaryKey(Long id) {
		return devicesMapper.selectByPrimaryKey(id);
	}

	@Override
	public void checkServiceIsExpired(ClientAuthentication authentication) {
		UsersInfoDetails usersInfoDetails = (UsersInfoDetails) authentication
				.getPrincipal();
		Long appId = usersInfoDetails.getAppId();
		ClientInfo clientInfo = null;
		try {
			clientInfo = clientInfoMapper.selectByPrimaryKey(Long
					.valueOf(appId));
		} catch (NumberFormatException e) {
			throw new ClientNotFoundException("AppId " + authentication
					+ " not found");
		}
		if (clientInfo == null) {
			throw new ClientNotFoundException("AppId " + authentication
					+ " not found");
		}
		if (clientInfo.getServiceExpiredDt() == null) {
			return;
		} else {
			Date expiredDt = clientInfo.getServiceExpiredDt();
			Date now = new Date();
			if (now.after(expiredDt)) {
				String msg = "App "
						+ clientInfo.getAppName()
						+ " service is expired,Please contact your service provider";
				throw new InvalidClientException(msg);
			}
		}
	}

	@Override
	public void updateLastActivityDt(ClientAuthentication auth) {
		UsersInfoDetails usersInfoDetails = (UsersInfoDetails) auth
				.getPrincipal();
		Long userId = usersInfoDetails.getId();
		UsersInfoDetails record = new UsersInfoDetails();
		record.setId(userId);
		record.setLastActivityDt(new Date());
		usersInfoDetailsMapper.updateByPrimaryKeySelective(record);
	}
}
